package experiment;
/**
 *  Structure where the information is stored to generate the xml experiment file
 *
 *  
 *  @author NetLogo
 */


// beware! we are Cloneable, but clone() makes a shallow copy,
// so we may wind up sharing our metrics array and our valueSets
// map with other instances.  - ST 12/18/04


import java.io.IOException;
import java.util.Iterator;

//import org.nlogo.util.Version;
import org.xml.sax.SAXException;

public strictfp class Protocol
	implements Cloneable
{

	public String name = "" ;
	public String setupCommands = "" ;
	public String goCommands = "" ;
	public String finalCommands = "" ;
	public int repetitions = 1 ;
	public boolean runMetricsEveryStep = true ;

	public boolean hasTimeLimit = false ;
	public int timeLimit = 0 ;

	public boolean hasExitCondition = false ;
	public String exitCondition = "" ;

	public String[] metrics = new String[] { } ;

	// maps from variable names (String) to ValueSets
	public java.util.Map valueSets = new java.util.LinkedHashMap() ;

	public String toString()
	{
		return super.toString() + ":'" + name + "'" ;
	}

	public String displayName()
	{
		int runs = countRuns() ;
		StringBuffer buf = new StringBuffer( name ) ;
		buf.append( " (" ) ;
		buf.append( Integer.toString( runs ) ) ;
		buf.append( " run" );
		if( runs != 1 )
		{
			buf.append( 's' ) ;
		}
		buf.append( ')' ) ;
		return buf.toString() ;
	}

//	public Object clone()
//	{
//		try
//		{
//			return (Protocol) super.clone() ;
//		}
//		catch( CloneNotSupportedException ex )
//		{
//			//throw new org.nlogo.util.UnexpectedException( ex ) ;
//		}
//	}

	///

	public int countRuns()
	{
		int result = 0 ;
		for( Iterator iter = iterator() ; iter.hasNext() ; )
		{
			iter.next() ;
			result++ ;
		}
		return result ;
	}

	///

	// this gets a bit complicated, but it's well encapsulated --
	// it iterates through all possible combinations of values
	// for the sliders and so forth - ST 8/20/03

	CombinationsIterator iterator()
	{
		return new CombinationsIterator() ;

	}

	class CombinationsIterator
		implements Iterator
	{
		private final String[] variableNames = new String[ valueSets.size() ] ;
		private final Iterator[] valueSetIterators =
			new Iterator[ valueSets.size() ] ;
		private Object[] currentValues = new Object[ valueSets.size() ] ;
		private int repetitionNumber = repetitions ;
		private Object lastResult ;
		CombinationsIterator()
		{
			Iterator iter = valueSets.keySet().iterator() ;
			for( int i = 0 ; i < valueSets.size() ; i++ )
			{
				variableNames[ i ] = (String) iter.next() ;
				ValueSet valueSet =
					(ValueSet) valueSets.get( variableNames[ i ] ) ;
				valueSetIterators[ i ] = valueSet.iterator() ;
				currentValues[ i ] = valueSetIterators[ i ].next() ;
			}
		}
		public boolean hasNext()
		{
			return currentValues != null || repetitionNumber < repetitions ;
		}
		public Object next()
		{
			if( repetitionNumber < repetitions )
			{
				repetitionNumber++ ;
				return lastResult ;
			}
			repetitionNumber = 1 ;
			Object[] resultArray = (Object[]) currentValues.clone() ;
			int last = findIndexOfLastIteratorWithNext() ;
			if( last == -1 )
			{
				currentValues = null ;
			}
			else
			{
				for( int i = last ; i < variableNames.length ; i++ )
				{
					if( i > last )
					{
						valueSetIterators[ i ] =
							( (ValueSet) valueSets.get( variableNames[ i ] ) )
							.iterator() ;
					}
					currentValues[ i ] = valueSetIterators[ i ].next() ;
				}
			}
			java.util.Map result = new java.util.LinkedHashMap() ;
			for( int i = 0 ; i < resultArray.length ; i++ )
			{
				result.put( variableNames[ i ] , resultArray[ i ] ) ;
			}
			lastResult = result ;
			return result ;
		}
		public void remove()
		{
			throw new UnsupportedOperationException() ;
		}
		private int findIndexOfLastIteratorWithNext()
		{
			for( int i = valueSetIterators.length - 1 ; i >= 0 ; i-- )
			{
				if( valueSetIterators[ i ].hasNext() )
				{
					return i ;
				}
			}
			return -1  ;
		}

	}

//	public static Protocol protocol( java.io.File file )
//		throws SAXException, IOException
//	{
//		java.util.List protocols = new java.util.ArrayList() ;
//		new ProtocolLoader( protocols , null , Version.noVersion() )
//			.load( file ) ;
//		if( protocols.size() != 1 )
//		{
//			throw new IllegalStateException
//				( "\"" + file + "\" contains more than one experiment setup" ) ;
//		} 
//		return (Protocol) protocols.get( 0 ) ;
//	}
//
//	public static Protocol protocol( String xml )
//		throws SAXException
//	{
//		
//		java.util.List protocols = new java.util.ArrayList() ;
//		new ProtocolLoader( protocols , null , Version.noVersion() )
//			.load( xml ) ;
//		if( protocols.size() != 1 )
//		{
//			throw new IllegalStateException
//				( "the XML contains more than one experiment setup" ) ;
//		}
//		return (Protocol ) protocols.get( 0 ) ;
//	}
//
//	
//	public static Protocol protocolByName( java.io.File file, String name )
//		throws SAXException, IOException
//	{
//		java.util.List protocols = new java.util.ArrayList() ;
//		new ProtocolLoader( protocols , null , Version.noVersion() )
//			.load( file ) ;
//		for( Iterator it = protocols.iterator() ; it.hasNext() ; )
//		{
//			Protocol protocol = (Protocol) it.next() ;
//			if( protocol.name.equals( name ) )
//			{
//				return protocol ;
//			}
//		}
//		throw new IllegalStateException
//			( "no experiment named \"" + name + "\" " +
//			  "found in \"" + file + "\"" ) ;
//	}
//
//	
//	public static Protocol protocolByName( String xml, String name )
//		throws SAXException, IOException
//	{
//		java.util.List protocols = new java.util.ArrayList() ;
//		new ProtocolLoader( protocols , null , Version.noVersion() )
//			.load( xml ) ;
//		for( Iterator it = protocols.iterator() ; it.hasNext() ; )
//		{
//			Protocol protocol = (Protocol) it.next() ;
//			if( protocol.name.equals( name ) )
//			{
//				return protocol ;
//			}
//		}
//		throw new IllegalStateException
//			( "no experiment named \"" + name ) ;
//	}

}
